package cn.wzy.dao;


import cn.wzy.common.PageInfo;
import cn.wzy.utils.MyDataBase;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * @author nihaowzy
 */
public class BaseDao<T> {
    /**
     * 查询所有的数据
     * @param sql
     * @param clazz
     * @param params
     * @return
     * @throws Exception
     */
    public List<T> selectAll(String sql , Class<T> clazz , Object... params) throws Exception {
        List<T> list = new ArrayList<>(10);

        try(
                Connection conn = MyDataBase.getConnection();
                PreparedStatement prep = conn.prepareStatement(sql)
        ){
            //将参数注入到？号参数中
            for (int i = 0; i < params.length ; i++) {
                prep.setObject(i+1,params[i]);
            }
            try(
                    ResultSet rs = prep.executeQuery();
            ){
                //获取元数据
                ResultSetMetaData metaData = rs.getMetaData();
                //获取总列数
                int columnCount = metaData.getColumnCount();
                while (rs.next()){
                    //通过反射 class类型参数clazz 获取实际对象
                    Constructor<T> constructor = clazz.getConstructor();
                    T t = constructor.newInstance();
                    for (int i = 0; i < columnCount ; i++) {
                        //获取每一列的值
                        Object value = rs.getObject(i + 1);
                        //获取每一列的列别名
                        String columnLabel = metaData.getColumnLabel(i + 1);
                        //通过反射获取对象的属性字段
                        Field field = clazz.getDeclaredField(columnLabel);
                        //通过暴力反射将每一列的值注入到对象的属性字段中
                        field.setAccessible(true);
                        field.set(t,value);
                    }
                    list.add(t);
                }
            }
            return list;
        }
    }

    /**
     * 查询某一条数据
     * @param sql
     * @param clazz
     * @param params
     * @return
     * @throws Exception
     */
    public T selectOne(String sql ,Class<T> clazz , Object... params) throws Exception {
        List<T> list = this.selectAll(sql, clazz, params);
        if (list.size() > 1){
            new RuntimeException("查询不是一条数据");
        }
        if (list.size() == 1){
            return list.get(0);
        }
        return null;
    }

    /**
     * 修改表中的数据
     * @param sql
     * @param params
     * @return
     * @throws Exception
     */
    public Integer update(String sql , Object... params) throws Exception {
        try(
                Connection connection = MyDataBase.getConnection();
                PreparedStatement prep = connection.prepareStatement(sql)
        ){
            for (int i = 0; i < params.length; i++) {
                prep.setObject(i+1,params[i]);
            }
            int result = prep.executeUpdate();

            return result;
        }
    }

    /**
     * 获取满足条件的数据的个数
     *
     * 例如sql语句 ：
     * select count(1)
     * from (select id, name, sex, age, city, descp
     *       from student
     *       where 1 = 1 and name = '小樱' and age in (23,43) and city = '北京') r;
     * @param sql
     * @return
     */
    public Integer selectCount(String sql) throws Exception {
         sql = "select count(1) from("+sql+") as rs";
        try(
                 Connection connection = MyDataBase.getConnection();
                 PreparedStatement prep = connection.prepareStatement(sql);
                 ResultSet rs = prep.executeQuery()
        ){
            //移动数据指针
            rs.next();
            //查询的结果为单行单列
            int count = rs.getInt(1);
            //返回指定查询的条数
            return count;
        }
    }

    /**
     * 查询当前页码的所有数据
     * @param sql
     * @param clazz 查询数据的类型
     * @param page 页码数
     * @param limit 每页显示数据的条数
     * @return
     */
    public PageInfo<T> selectPage(String sql , Class<T> clazz , Integer page , Integer limit) throws Exception {
        //一共有多少条数据
        Integer count = this.selectCount(sql);
        //开始查询的索引
        Integer pageNo = (page - 1)*limit;
        //limit pageNO , limit // pageNo 开始查询的索引 ，limit 每页查询的数据条数
        sql = sql + " limit "+pageNo+","+limit;
        List<T> list = this.selectAll(sql, clazz);
        return new PageInfo<T>(page,limit,list,count);
    }

    @Test
    public void  test1() throws Exception {

    }

}
